package com.jwcao.common.cast.operation;

import com.jwcao.common.cast.annotation.CastObject;
import com.jwcao.common.cast.annotation.factory.CastObjectFactory;
import com.jwcao.common.cast.operation.access.AccessOperation;
import com.jwcao.common.cast.operation.access.MethodAccessOperation;
import com.jwcao.common.cast.operation.access.MethodAccessOperationFactory;
import com.jwcao.common.cast.operation.access.field.FieldAccessOperationFactory;
import com.jwcao.common.cast.operation.callback.CallBackOperationFactory;
import com.jwcao.common.cast.operation.callback.ToCallBackOperation;
import com.jwcao.common.cast.operation.injection.InjectionOperation;
import com.jwcao.common.cast.operation.injection.InjectionOperationFactory;
import com.jwcao.common.cast.operation.instance.ArgInstanceOperation;
import com.jwcao.common.cast.operation.instance.InstanceOperation;
import com.jwcao.common.cast.operation.instance.InstanceOperationFactory;
import com.jwcao.common.scan.object.ScanClass;
import java.util.ArrayList;
import java.util.List;

/**
 * name: CastFlowFactory description: TODO
 *
 * @author caojingwei date: 2023/3/24 16:54
 */
public class CastFlowFactory {

    public static CastFlow get(String id, ScanClass sourceClass, ScanClass targetClass) {
        CastObject aCastObject = CastObjectFactory.get(id, sourceClass.getClazz(), targetClass.getClazz());
        if (aCastObject != null) {
            return getTo(id, sourceClass, targetClass);
        }
        //TODO:: 这里应该处理异常
        return null;
    }

    /**
     * A -> B  注解在 A 中
     */
    public static CastFlow getTo(String id, ScanClass sourceClass, ScanClass targetClass) {
        // 获取所有字段
        List<AccessOperation> fieldAccessOperationList = FieldAccessOperationFactory.get(id, sourceClass, targetClass);
        // 获取所有方法
        List<MethodAccessOperation> methodAccessOperationList = MethodAccessOperationFactory.get(id, sourceClass, targetClass);
        List<AccessOperation> accessOperationList = new ArrayList<>();
        accessOperationList.addAll(fieldAccessOperationList);
        accessOperationList.addAll(methodAccessOperationList);

        InstanceOperation instanceOperation = InstanceOperationFactory.get(id, targetClass, accessOperationList);
        if (instanceOperation instanceof ArgInstanceOperation argInstanceOperation) {
            // 排除掉已经用构造函数注入过的值
            accessOperationList = argInstanceOperation.excludeInjectionOperation(accessOperationList);
        }

        List<InjectionOperation> injectionOperationList = InjectionOperationFactory.get(id, targetClass,
            accessOperationList);

        ToCallBackOperation toCallBackOperation = CallBackOperationFactory.getTo(id, sourceClass);

        return new CastFlow(id, sourceClass, targetClass, instanceOperation, injectionOperationList, null, toCallBackOperation);
    }
}
